home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / MWCC03 / HOTKEY1.ZIP / HOTKEY1.PAS < prev    next >
Pascal/Delphi Source File  |  1993-08-18  |  24KB  |  707 lines

  1. {**********************************************************************}
  2. {*                                                                    *}
  3. {*          Microworks Sample Application                                        *}
  4. {*                                                                    *}
  5. {*         for Borland Pascal v7.0 and Turbo Pascal for Windows v1.5           *}
  6. {*                                                                    *}
  7. {*     Copyright 1992-93 Jeff Franks (Microworks) Sydney, Australia.  *}
  8. {*                                                                    *}
  9. {*         You are free to use, modify, reproduce and distribute the      *}
  10. {*         Sample Files (and/or any modified version) in any way you      *}
  11. {*         find useful.                                                                *}
  12. {*                                                                    *}
  13. {**********************************************************************}
  14.  
  15. {*** Introduction
  16.  
  17.     Application    := Application specific hotkey edit control
  18.  
  19.     Files          := Hotkey1.exe, Hotkey1.pas, Hotkey1.res
  20.  
  21.     Units Required := MObjects and MWCC.dll
  22.  
  23.     Purpose        := HotKey1 shows you how to,
  24.  
  25.                                      1. Install a 'task' hook using the new 'SetWindowHookEx' function.
  26.  
  27.                                      2. Set up the associated application 'Callback' function.
  28.  
  29.                                      3. Set up an application HotKey.
  30.  
  31.                                      4. Use some of the objects in the MWCC library.
  32.  
  33.     Tabs           := 2
  34.  
  35.     Screen         := 800 * 600
  36.  
  37.     Date           := August, 1993.
  38.  
  39.     Hotkey1 is a translation of the C program 'Shortcut Key Edit Sample' available on the
  40.     MSDNLIB forum as 4-52.zip. I translated the program in the hope of sovling a problem. It
  41.     didn't solve my problem but it did provide a useful utility. This is my first attempt at
  42.     translating a C program - What a nightmare!
  43.  
  44.     I have kept this translation true to the original. The only change apart from the OWL
  45.     conversion is the use of my own custom contols. The MWCC object units and library do not
  46.     require BWCC.DLL or Ctl3D.DLL.
  47.  
  48.     The Hotkey in this program is only valid for the application. When the application
  49.     looses the focus the Hot key doesn't work. The other example 'Hotkey2'
  50.     is my own work. It installs a system wide hot key that works whether the application
  51.     has the focus or not.
  52.  
  53.     I hope you find HotKey1 useful.
  54.  
  55.     Jeff...
  56.  
  57. ***}
  58.  
  59. program HotKey1;
  60.  
  61. {$R HotKey1.Res}
  62. {$C Demandload Moveable Discardable}
  63.  
  64. uses WinTypes, WinProcs, Strings, Win31, MObjects,
  65.          {$IFDEF Ver15}
  66.              WObjects;
  67.          {$ELSE}
  68.              Objects, OWindows, ODialogs;
  69.          {$ENDIF}
  70.  
  71. const
  72.  
  73.     {*** Window ID's ***}
  74.     idw_timer                       = 101;
  75.  
  76.     {*** Dialog ID's ***}
  77.     idd_HotKeyEdit                  = 401;
  78.     idd_Static1                     = 402;
  79.     idd_Static2                     = 403;
  80.     idd_Static3                     = 404;
  81.     idd_Install                     = 405;
  82.  
  83.     {*** Menu ID's ***}
  84.     idm_About                       = 701;
  85.     idm_EditInstallHotKey           = 702;
  86.     idm_RemoveHotKey                = 703;
  87.  
  88.     {*** User defined messages ***}
  89.     wm_Hotkey                       = wm_User + 1;
  90.     wm_InstallHotKey                = wm_User + 2;
  91.  
  92.     {*** far declaration for Callback function ***}
  93.     pToHotKeyHookProc : TFarProc    = nil;
  94.  
  95.     {*** Speaks for itself ***}
  96.     AppName : PChar                 = 'HotKey1';
  97.  
  98. type
  99.  
  100.     THotKeyStruct = record
  101.         wMenuKey          : Word;
  102.         wControlKey       : Word;
  103.         wShiftKey         : Word;
  104.         wKey              : Word;
  105.         wKeyNum           : Word;
  106.         szText, szKeyName : array[0..30] of Char;
  107.     end;
  108.  
  109.     PAboutDialog = ^TAboutDialog;
  110.     TAboutDialog = object(TSFXDialog)
  111.         {***
  112.  
  113.             TMWCCBmpButton is a BWCC style bitMap button object. TMWCCStatic is a static object
  114.             that displays either raised, recessed or normal static controls. WMDrawItem is required
  115.             to draw the TMWCCBmpButton ownerdraw button object.
  116.  
  117.         ***}
  118.         OkBut    : PMWCCBmpButton;
  119.         ST1, ST2 : PMWCCStatic;
  120.         constructor Init (AParent: PWindowsObject; AName: PChar);
  121.         procedure SetUpWindow; virtual;
  122.         procedure WMDrawItem (var Msg: TMessage); virtual wm_First + wm_DrawItem;
  123.     end;
  124.  
  125.     PHotKeyEdit = ^THotKeyEdit;
  126.     THotKeyEdit = object(TEdit)
  127.         {***
  128.  
  129.             If you make THotKeyEdit a descendant of TMWCCEdit you will get a recessed edit control.
  130.  
  131.         ***}
  132.         procedure DefWndProc (var Msg : TMessage); virtual;
  133.         procedure DisplayHotKey (var wModifierKey : Word);
  134.         procedure ResetHotKey; virtual;
  135.         procedure EraseHotKey; virtual;
  136.     end;
  137.  
  138.     PHotKeyEditDialog = ^THotKeyEditDialog;
  139.     THotKeyEditDialog = object(TSFXDialog)
  140.         {***
  141.  
  142.             THotKeyEditDialog is where you enter the Hotkey combination. It is a descendant of
  143.             TSFXDialog (SpecialFX Dialog) which is one of the MWCC custom objects. SFX objects
  144.             don't support menu's or TScroller scroll bars.
  145.  
  146.         ***}
  147.         EC            : PHotKeyEdit;
  148.         ST1, ST2, ST3 : PMWCCStatic;
  149.         But1, But2    : PMWCCBmpButton;
  150.         constructor Init(AParent: PWindowsObject; AName: PChar);
  151.         procedure IDDInstall (var Msg: TMessage); virtual id_First + idd_Install;
  152.         procedure SetUpWindow; virtual;
  153.         procedure WMDrawItem (var Msg: TMessage); virtual wm_First + wm_DrawItem;
  154.     end;
  155.  
  156.     PHotKeyWindow = ^THotKeyWindow;
  157.     THotKeyWindow = object(TWindow)
  158.         CyanBrush, RedBrush : HBrush;
  159.         CyanBkGround        : Boolean;
  160.         WindowNotActive     : Boolean;
  161.         WinMenu             : HMenu;
  162.         constructor Init (AParent: PWindowsObject; AName: PChar);
  163.         destructor Done; virtual;
  164.         function  GetClassName : PChar; virtual;
  165.         procedure GetWindowClass (var AWndClass: TWndClass); virtual;
  166.         procedure IDMEditInstallHotKey (var Msg: TMessage); virtual cm_First + idm_EditInstallHotKey;
  167.         procedure IDMRemoveHotKey (var Msg: TMessage); virtual cm_First + idm_RemoveHotKey;
  168.         procedure IDMAbout (var Msg: TMessage); virtual cm_First + idm_About;
  169.         procedure WMInstallHotKey (var Msg: TMessage); virtual wm_First + wm_InstallHotKey;
  170.         procedure RemoveHotKey; virtual ;
  171.         procedure WMHotKey (var Msg: TMessage); virtual wm_First + wm_HotKey;
  172.         procedure WMTimer  (var Msg: TMessage); virtual wm_First + wm_Timer;
  173.     end;
  174.  
  175.     PHotKeyApplication = ^THotKeyApplication;
  176.     THotKeyApplication = object(TApplication)
  177.         procedure InitMainWindow; virtual;
  178.     end;
  179.  
  180. var
  181.  
  182.     HotKeyRec   : THotKeyStruct;
  183.     HHotKeyHook : HHook;
  184.  
  185. {********** THotKeyApplication **********}
  186.  
  187. procedure THotKeyApplication.InitMainWindow;
  188. begin
  189.     MainWindow := New(PHotKeyWindow, Init(nil, 'HotKey 1 Window - HotKey = None'));
  190. end;
  191.  
  192. {********** Callback function **********}
  193.  
  194. function HotKeyHookProc (nCode: Integer; wParam: Word; lParam: LongInt): LongInt; Export;
  195. {***
  196.  
  197.     When a key is pressed this callback function checks to see if the key pressed (wParam)
  198.     is the same as that stored in the wKey field of the HotKeyStruct record. If it is and the
  199.     appropriate modifier key (Ctrl, Shift +/or Alt) is down a wm_HotKey message is sent to the main
  200.     window. WMHotkey is the end result of the hook. Here it just flashes the background colour
  201.     from cyan to red but it could be used to launch an application or run a menu item.
  202.  
  203.     CallNexthookEx ensures that any unwanted trapped information gets passed onto the
  204.     the next hook in the system;
  205.  
  206. ***}
  207. label
  208.     Exit;
  209. var
  210.     HotKeyWin : HWnd;
  211. begin
  212.     if (nCode = hc_Action) and (HotKeyRec.wKey = WParam) then
  213.     begin
  214.         {*** Exits if the Key was released or if it's a repeat ***}
  215.         if (lParam = $80000000) or (lParam = $40000000) then
  216.             goto Exit;
  217.         {*** Check to see if ALT is part of the shortcut key and pressed ***}
  218.         if HotKeyRec.wMenuKey = 1 then
  219.             if HI(GetKeyState(vk_Menu)) = 0 then goto Exit;
  220.         {*** Check to see if Control is part of the shortcut key and pressed ***}
  221.         if HotKeyRec.wControlKey = 1 then
  222.             if HI(GetKeyState(vk_Control)) = 0 then goto Exit;
  223.         {*** Check to see if Shift is part of the shortcut key and pressed ***}
  224.         if HotKeyRec.wShiftKey = 1 then
  225.             if HI(GetKeyState(vk_Shift)) = 0 then goto Exit;
  226.         HotKeyWin := FindWindow('HotKeyWindow', nil);
  227.         PostMessage(HotKeyWin, wm_HotKey, 0, 0);
  228.     end;
  229.  
  230.     Exit:
  231.         HotKeyHookProc := CallNextHookEx(HHotKeyHook, nCode, WParam, Longint(@LParam));
  232. end;
  233.  
  234. {********** THotKeyWindow **********}
  235.  
  236. constructor THotKeyWindow.Init(AParent: PWindowsObject; AName: PChar);
  237. begin
  238.     TWindow.Init(AParent, AName);
  239.     {*** Makes the window a nice size for the screen ***}
  240.     Attr.X := GetSystemMetrics(sm_CXScreen) div 6;
  241.     Attr.Y := GetSystemMetrics(sm_CYScreen) div 6;
  242.     Attr.W := GetSystemMetrics(sm_CXScreen) div 3 * 2;
  243.     Attr.H := GetSystemMetrics(sm_CYScreen) div 3 * 2;
  244.     {*** Sets the hook to zero ***}
  245.     HHotKeyHook := 0;
  246.     {*** Sets the fields of THotKeyStruc to zero ***}
  247.     HotKeyRec.wMenuKey := 0;
  248.     HotKeyRec.wControlKey := 0;
  249.     HotKeyRec.wShiftKey := 0;
  250.     HotKeyRec.wKey := 0;
  251.     {*** Creates the two brushes used to paint the background ***}
  252.     CyanBrush := CreateSolidBrush (RGB (0, 128, 128));
  253.     RedBrush := CreateSolidBrush (RGB (255, 0, 0));
  254.     {*** Lets the window know that the background is initially cyan ***}
  255.     CyanBkGround := True;
  256. end;
  257.  
  258. destructor THotKeyWindow.Done;
  259. begin
  260.     RemoveHotKey;
  261.     DeleteObject(CyanBrush);
  262.     DeleteObject(RedBrush);
  263.     TWindow.Done;
  264. end;
  265.  
  266. function THotKeyWindow.GetClassName;
  267. begin
  268.     GetClassName := 'HotKeyWindow';
  269. end;
  270.  
  271. procedure THotKeyWindow.GetWindowClass(var AWndClass: TWndClass);
  272. begin
  273.     TWindow.GetWindowClass(AWndClass);
  274.     AWndClass.hIcon := LoadIcon(HInstance, 'HotKeyEditIcon');
  275.     AWndClass.lpszMenuName := PChar('HotKeyEditMenu');
  276.     AWndClass.HBrBackground := CyanBrush;
  277. end;
  278.  
  279. procedure THotKeyWindow.IDMEditInstallHotKey(var Msg: TMessage);
  280. {***
  281.  
  282.     Launches the hotkey dialog box. If the return value is 1 then the install button
  283.     was pressed and the Remove menu item is enabled.
  284.  
  285. ***}
  286. var
  287.     ADlg: PHotKeyEditDialog;
  288. begin
  289.     WinMenu := GetMenu(HWindow);
  290.     ADlg := New(PHotKeyEditDialog, Init(@Self, 'HotKeyEditBox'));
  291.     if (Application^.ExecDialog(ADlg) = 1) then
  292.         EnableMenuItem(WinMenu, idm_RemoveHotKey, mf_ByCommand  or mf_Enabled);
  293. end;
  294.  
  295. procedure THotKeyWindow.IDMRemoveHotKey(var Msg: TMessage);
  296. {***
  297.  
  298.     Removes the  installed hotkey and disables the 'Remove' menu item.
  299.  
  300. ***}
  301. begin
  302.     RemoveHotKey;
  303.     WinMenu := GetMenu(HWindow);
  304.     EnableMenuItem(WinMenu, idm_RemoveHotKey, mf_ByCommand  or mf_Grayed);
  305. end;
  306.  
  307. procedure THotKeyWindow.IDMAbout(var Msg: TMessage);
  308. begin
  309.     Application^.ExecDialog(New(PABoutDialog, Init(@Self, 'AboutBox')));
  310. end;
  311.  
  312. procedure THotKeyWindow.WMInstallHotKey(var Msg: TMessage);
  313. {*** Hook
  314.  
  315.     pToHotKeyHookProc points to the memory address of the HotKeyHookProc callback function.
  316.     SetWindowHookEx install a task only wh_keyboard hook and sets the hook to the current task.
  317.     szCaption sets the new caption to include the installed hotkey and SetTimer sets the timer
  318.     thats used to flash the title bar (window).
  319.  
  320. ***}
  321. var
  322.     szCaption : array[0..80] of Char;
  323.     CharStr   : PChar;
  324. begin
  325.     if HHotKeyHook = 0 then
  326.     begin
  327.         pToHotKeyHookProc := TFarProc(@HotKeyHookProc);
  328.         HHotKeyHook := SetWindowsHookEx(wh_Keyboard, THookProc(pToHotKeyHookProc),
  329.                                                                                                 hInstance, GetCurrentTask);
  330.         CharStr := HotKeyRec.szText;
  331.         wvsprintf(szCaption, 'HotKeyEdit 1 - HotKey = %s', CharStr);
  332.         SetTimer(HWindow, idw_Timer, 1000, nil);
  333.         SetWindowText(HWindow, szCaption);
  334.     end
  335.     else
  336.     begin
  337.         {*** Update title
  338.  
  339.             If the Hook is already present just the title gets updated when you install a new Hotkey.
  340.  
  341.         ***}
  342.         CharStr := HotKeyRec.szText;
  343.         wvsprintf(szCaption, 'HotKey 1 Window - HotKey = %s', CharStr);
  344.         SetWindowText(HWindow, szCaption);
  345.     end;
  346. end;
  347.  
  348. procedure THotKeyWindow.RemoveHotKey;
  349. {*** Unhook
  350.  
  351.      UnhookWindowsHookEx unhooks the hook identifed by the handle 'HHotKeyHook'
  352.      when the remove menu item is selected. SetWindowText restores the previous title.
  353.      Killtimer removes the timer used to flash the title bar and the FlashWindow
  354.      function is turned off.
  355.  
  356. ***}
  357. begin
  358.     if HHotKeyHook <> 0 then
  359.     begin
  360.         UnhookWindowsHookEx(HHotKeyHook);
  361.         HHotKeyHook := 0;
  362.         HotKeyRec.wMenuKey := 0;
  363.         HotKeyRec.wControlKey := 0;
  364.         HotKeyRec.wShiftKey := 0;
  365.         SetWindowText(HWindow, 'HotKey 1 Window - HotKey = None');
  366.         KillTimer(HWindow, idw_Timer);
  367.         if WindowNotActive = True then FlashWindow(HWindow, False);
  368.     end;
  369. end;
  370.  
  371. procedure THotKeyWindow.WMHotKey(var Msg: TMessage);
  372. {***
  373.  
  374.     This is the wm_hotkey user defined message that is sent from the callback function.
  375.     It changes the colour of the background when the hotkey is pressed. You could use
  376.     it to launch an application or run a menu item.
  377.  
  378. ***}
  379. begin
  380.     if CyanBkGround then
  381.         SetClassWord(HWindow, gcw_HBrBackground, RedBrush)
  382.     else
  383.         SetClassWord(HWindow, gcw_HBrBackground, CyanBrush);
  384.     InvalidateRect(HWindow, nil, True);
  385.     UpdateWindow(HWindow);
  386.     CyanBkGround := not CyanBkGround;
  387. end;
  388.  
  389. procedure THotKeyWindow.WMTimer(var Msg: TMessage);
  390. begin
  391.     if Msg.WParam = idw_Timer then
  392.         WindowNotActive := FlashWindow(HWindow, True);
  393. end;
  394.  
  395. {********** THotKeyEditDialog **********}
  396.  
  397. constructor THotKeyEditDialog.Init(AParent: PWindowsObject; AName: PChar);
  398. {***
  399.  
  400.     Any MWCC object used in your program must have a unique id numder and be initialised.
  401.     You can't just place them there with a -1 id like you can when you use BWCC.dll.
  402.  
  403.     Here 3 TMWCCStatic objects are initialised and used to display a recessed frame.
  404.     You could display a raised frame by replacing 'ctl_Recessed' with 'ctl_Raised'. Since
  405.     they're used as frames their text length is set to zero.
  406.  
  407.     TMWCCStatic is always light gray in colour. If you wanted to use it for text you would
  408.     set the appropiate text length and use 'ctl_Static' constant. TMWCCStatic text objects
  409.     are always flat.
  410.  
  411.     'ctl_Flush' paints a border around  a bitmapped button so that it appears reccessed.
  412.      If you don't want a recessed button enter '0' instead. The second last field, the number's
  413.      23 and 2 identify one of the predefined bitmapped buttons in MWCC.dll. 2 is the cancel
  414.      button and 23 is the install button. The buttons use the BWCC style and numbering system.
  415.  
  416.      I use 'GetSystemMetrics(sm_CYSize) = 26' to test for screen resolution. When you use
  417.      bitmaps in dialogs there size and positon doesn't change between screen resolutions but
  418.      the size of the dialog box does. This results in skewed controls - say if you design a
  419.      dialog in vga or supervga (fonts.fon=vgasys.fon in system.ini) and the user displays the
  420.      dialog in extended vga (fonts.fon=8514sys.fon in system.ini). The menu bar bitmap is
  421.      26 pixels high in extended vga (1024 * 768) and less in vga and supervga. If sm_CYSize = 26
  422.      I move the buttons so that the dialog box looks right.
  423.  
  424. ***}
  425. begin
  426.     TSFXDialog.Init(AParent, AName);
  427.     ST1 := New(PMWCCStatic, InitResource(@Self, idd_Static1, 0, ctl_Recessed));
  428.     ST2 := New(PMWCCStatic, InitResource(@Self, idd_Static2, 0, ctl_Recessed));
  429.     ST3 := New(PMWCCStatic, InitResource(@Self, idd_Static3, 0, ctl_Recessed));
  430.     EC := New(PHotKeyEdit, InitResource(@Self, idd_HotkeyEdit, 30));
  431.     if GetSystemMetrics(sm_CYSize) = 26 then
  432.     begin
  433.         But1 := New(PMWCCBmpButton, Init(@Self, idd_Install, 106, 284, False, 101, ctl_Flush));
  434.         But2 := New(PMWCCBmpButton, Init(@Self, id_Cancel, 282, 284, False, 2, ctl_Flush));
  435.     end
  436.     else
  437.     begin
  438.         But1 := New(PMWCCBmpButton, Init(@Self, idd_Install, 72, 226, False, 101, ctl_Flush));
  439.         But2 := New(PMWCCBmpButton, Init(@Self, id_Cancel, 216, 226, False, 2, ctl_Flush));
  440.     end;
  441. end;
  442.  
  443. procedure THotKeyEditDialog.SetUpWindow;
  444. {***
  445.  
  446.     CenterOverClient is a useful procedure in MWCC.dll. It centres the dialog over
  447.     the client area of the parent window. EnableWindow ensures the install button is disabled
  448.     when the dialog fist appears.
  449.  
  450. ***}
  451. begin
  452.     TSFXDialog.SetUpWindow;
  453.     CenterOverClient(Parent^.HWindow, HWindow);
  454.     EnableWindow(But1^.HWindow, False);
  455. end;
  456.  
  457. procedure THotKeyEditDialog.WMDrawItem(var Msg:tMessage);
  458. {***
  459.  
  460.     WMDrawItem draws the ownerdraw button object TMWCCBmpButton. Without it you would only see a
  461.     blank square.
  462.  
  463. ***}
  464. begin
  465.   with PDrawItemStruct(Msg.lParam)^ do
  466.     case CtlType of
  467.       odt_Button:
  468.         case CtlID of
  469.                     idd_Install : But1^.DrawItem(Msg);
  470.                     id_Cancel : But2^.DrawItem(Msg);
  471.                 end;
  472.     end;
  473. end;
  474.  
  475. procedure THotKeyEditDialog.IDDInstall(var Msg: TMessage);
  476. {***
  477.  
  478.     This is the install button. When pressed the text in the edit control is copied to
  479.     the szText field of HotKeyRec. The user defined wm_InstallHotKey message is sent to the
  480.     mainwindow to install the hot key.
  481.  
  482. ***}
  483. begin
  484.     EC^.GetLine(HotKeyRec.szText, 30, 1);
  485.     PostMessage(Parent^.HWindow, wm_InstallHotKey, 0, 0);
  486.     EndDlg(1);
  487. end;
  488.  
  489. {********** THotKeyEdit **********}
  490.  
  491. procedure THotKeyEdit.DefWndProc(Var Msg : TMessage);
  492. {***
  493.  
  494.     This is where the action starts. I was able to replace the difficult to understand C stuff
  495.     with this function. It lets you intercept KeyBoard messages before DefWndProc handles
  496.     them. When a wm_Keydown or wm_SysKeyDown message occurs wModifierkey is set to that key.
  497.     If a modifier key (Ctrl, Shift or Alt) was not pressed or if only the shift key was pressed
  498.     the input is ignored. If the backspace key is pressed or if other unwanted keyboard
  499.     input occurs the entry is erased, otherwise the hotkey is displayed.
  500.  
  501. ***}
  502. var
  503.     wModifierKey : Word;
  504. begin
  505.     with Msg do
  506.         if (Message = wm_KeyDown) or (Message = wm_SysKeyDown) then
  507.         begin
  508.             wModifierKey := 0;
  509.             HotKeyRec.wKeyNum := Msg.wParam;
  510.             {***
  511.  
  512.                 Get key name and copy it into the HotKeyRec.szKeyName bufferfor use in 'DisplayHotkey'.
  513.  
  514.             ***}
  515.             if (GetKeyNameText(Msg.lParam, HotKeyRec.szKeyName, sizeof(HotKeyRec.szKeyName))) = 0 then
  516.                 HotKeyRec.szKeyName[0] := #0;
  517.             {*** Ignore key if one of the modifier keys is not pressed ***}
  518.             if (HI(GetKeyState(vk_Menu)) <> 0) or (HI(GetKeyState(vk_Control)) <> 0) or
  519.                      (HI(GetKeyState(vk_Shift)) <> 0) then
  520.                 wModifierKey := Msg.wParam;
  521.             {*** Ignore key if it's a reserved key ***}
  522.             if (Msg.wParam = vk_Tab) or (Msg.wParam = vk_Escape) or
  523.                  (Msg.wParam = vk_Return) or (Msg.wParam = vk_Space) then EraseHotKey
  524.             else
  525.             {*** Erase edit control if backspace key was pressed by itself ***}
  526.             if (Msg.wParam = vk_Back) and (wModifierKey = 0) then
  527.             begin
  528.                 EraseHotKey;
  529.                 EnableWindow(GetDlgItem(Parent^.HWindow, idd_Install), False);
  530.             end
  531.             else
  532.             if wModifierKey <> 0 then
  533.                 {*** Pass key to DisplayHotkey function ***}
  534.                 DisplayHotKey(wModifierKey);
  535.         end
  536.         else
  537.         if (Message = wm_KeyUp) or (Message = wm_SysKeyUp) or
  538.              (Message = wm_Char) or (Message = wm_SysChar) then
  539.         begin
  540.             {*** Pass reserved key input onto DefWndProc for normal processing ***}
  541.             if (Msg.wParam = vk_Return) or (Msg.wParam = vk_Escape) or (Msg.wParam = vk_Tab) then
  542.                 TEdit.DefWndProc(Msg);
  543.             {***
  544.  
  545.                 If only a modifier key was pressed and released or if only the shift key
  546.                 modifier is pressed ignore keys and erase edit control entry.
  547.  
  548.             ***}
  549.             if (HotKeyRec.wKey = 0) or ((HotKeyRec.wShiftKey = 1) and (HotKeyRec.wMenuKey = 0) and
  550.                  (HotKeyRec.wControlKey = 0) and (Msg.Message = wm_KeyUp)) then
  551.                 EraseHotKey;
  552.         end
  553.         else
  554.             TEdit.DefWndProc(Msg);
  555. end;
  556.  
  557. procedure THotKeyEdit.DisplayHotKey(var wModifierKey: Word);
  558. {***
  559.  
  560.     This function displays the Hotkey in then edit control. It's slightly different from the
  561.     original C program but it does the same job. It first makes sure the install button is
  562.     disabled and sets szHotKey buffer to zero. DisplayHotkey gets run everytime a valid key
  563.     is pressed. If the edit control is empty (like when you open or reopen the dialog) the
  564.     modifier key fields of THotKeyStruc are set to zero. This is so this example functions
  565.     properly. If a valid key is pressed its name is added to the szHotKey buffer and szHotKey
  566.     is set as the edit control text (the C Way). .
  567.  
  568. ***}
  569. var
  570.     szHotKey      : array[0..30] of Char;
  571.     iHotKeyStrLen : Integer;
  572.     EditWnd       : HWnd;
  573.     wKeyNum       : Word;
  574. begin
  575.     szHotKey[0] := #0;
  576.     wKeyNum := HotKeyRec.wKeyNum;
  577.     EnableWindow((GetDlgItem(Parent^.HWindow, idd_Install)), False);
  578.     if GetlineLength(1) = 0 then ResetHotKey;
  579.     if (HI(GetKeyState(vk_Menu)) <> 0) then
  580.         StrCopy(szHotKey, 'Alt');
  581.     if (HI(GetKeyState(vk_Control)) <> 0) then
  582.     begin
  583.         if (HI(GetKeyState(vk_Menu)) <> 0) then
  584.             StrCat(szHotKey, '+Ctrl')
  585.         else
  586.             StrCopy(szHotKey, 'Ctrl');
  587.     end;
  588.     if (HI(GetKeyState(vk_Shift)) <> 0) then
  589.     begin
  590.         if (HI(GetKeyState(vk_Menu)) <> 0) or
  591.          (HI(GetKeyState(vk_Control)) <> 0) then
  592.             StrCat(szHotKey, '+Shift')
  593.         else
  594.             StrCopy(szHotKey, 'Shift');
  595.     end;
  596.     EditWnd := (GetDlgItem(Parent^.HWindow, idd_HotKeyEdit));
  597.     SetWindowText(EditWnd, szHotKey);
  598.     {*** Set caret to the end of the line ***}
  599.     iHotKeyStrLen := StrLen(szHotKey);
  600.     SendMessage(EditWnd, em_SetSel, 0, MakeLong(iHotKeyStrLen, iHotKeyStrLen));
  601.     {***
  602.  
  603.         Sets the value of the modifier key fields in THotKeyStruc to '1'. These
  604.         fields are checked by the callback function everytime a key is pressed.
  605.  
  606.     ***}
  607.     if wModifierKey = vk_Menu then
  608.         HotKeyRec.wMenuKey := 1;
  609.     if wModifierKey = vk_Control then
  610.         HotKeyRec.wControlKey := 1;
  611.     if wModifierKey = vk_Shift then
  612.         HotKeyRec.wShiftKey := 1;
  613.     HotKeyRec.wKey := 0;
  614.     {*** Only let keys other than modifier keys go any further ***}
  615.     if (StrIComp(HotKeyRec.szKeyName, '') <> 0) and
  616.          ((wKeyNum <> vk_Menu) and (wKeyNum <> vk_Control) and (wkeyNum <> vk_Shift)) then
  617.     begin
  618.         StrCat(szHotKey, '+');
  619.         StrCat(szHotKey, HotKeyRec.szKeyName);
  620.         HotKeyRec.wKey := HotKeyRec.wKeyNum;
  621.         SetWindowText(EditWnd, szHotKey);
  622.         StrCopy(HotKeyRec.szText, szHotKey);
  623.         {***
  624.  
  625.             Checks to make sure that a single modifier key is not the shift key.
  626.             If it is we ignore it because Windows uses that key. If the key combination
  627.             is valid enable the install button.
  628.  
  629.         ***}
  630.         if (HotKeyRec.wMenuKey = 1) or (HotKeyRec.wControlKey = 1) then
  631.             EnableWindow((GetDlgItem(Parent^.HWindow, idd_Install)), True);
  632.         {*** Sets the caret to the end of the line ***}
  633.         iHotKeyStrLen := StrLen(szHotKey);
  634.         SendMessage(EditWnd, em_SetSel, 0, MakeLong(iHotKeyStrLen, iHotKeyStrLen));
  635.     end;
  636. end;
  637.  
  638. procedure THotKeyEdit.ResetHotKey;
  639. {*** Reset
  640.  
  641.     Sets the Hotkey fields to zero
  642.  
  643. ***}
  644. begin
  645.     HotKeyRec.wMenuKey := 0;
  646.     HotKeyRec.wControlKey := 0;
  647.     HotKeyRec.wShiftKey := 0;
  648.     HotKeyRec.wKey := 0;
  649. end;
  650.  
  651. procedure THotKeyEdit.EraseHotKey;
  652. {***
  653.  
  654.     Erases the entry in the edit control. (eg when the backspace key is pressed);
  655.  
  656. ***}
  657. begin
  658.     DeleteSubText(0, 30);
  659.     ResetHotKey;
  660. end;
  661.  
  662. {********** TAboutDialog **********}
  663.  
  664. constructor TAboutDialog.Init(AParent: PWindowsObject; AName: PChar);
  665. {***
  666.  
  667.     Does the same as the hotkey Edit Dialog box does. It initializes two recessed TMWCCStatic
  668.     objects and the BWCC style 'Ok Button' (id 1) in MWCC.dll.
  669.  
  670. ***}
  671. begin
  672.     TSFXDialog.Init(AParent, AName);
  673.     ST1 := New(PMWCCStatic, InitResource(@Self, idd_Static1, 0, ctl_Recessed));
  674.     ST2 := New(PMWCCStatic, InitResource(@Self, idd_Static2, 0, ctl_Recessed));
  675.     if GetSystemMetrics(sm_CYSize) = 26 then
  676.         OkBut := New(PMWCCBmpButton, Init(@Self, id_Ok, 460, 26, False, 1, ctl_Flush))
  677.     else
  678.         OkBut := New(PMWCCBmpButton, Init(@Self, id_Ok, 350, 21, False, 1, ctl_Flush));
  679. end;
  680.  
  681. procedure TAboutDialog.SetUpWindow;
  682. begin
  683.     TSFXDialog.SetUpWindow;
  684.     CenterOverClient(Parent^.HWindow, HWindow);
  685. end;
  686.  
  687. procedure TAboutDialog.WMDrawItem(var Msg:tMessage);
  688. begin
  689.     with PDrawItemStruct(Msg.lParam)^ do
  690.     case CtlType of
  691.       odt_Button:
  692.         case CtlID of
  693.                     id_Ok : OkBut^.DrawItem(Msg);
  694.                 end;
  695.     end;
  696. end;
  697.  
  698. {********** Main program **********}
  699.  
  700. var
  701.     HKApp: THotKeyApplication;
  702. begin
  703.     HKApp.Init(AppName);
  704.     HKApp.Run;
  705.     HKApp.Done;
  706. end.
  707.